/* command.c, created from command.def. */
#line 22 "./command.def"

#line 41 "./command.def"

#include <config.h>

#if defined (HAVE_UNISTD_H)
#  ifdef _MINIX
#    include <sys/types.h>
#  endif
#  include <unistd.h>
#endif

#include "../bashansi.h"

#include "../shell.h"
#include "../execute_cmd.h"
#include "../flags.h"
#include "bashgetopt.h"
#include "common.h"

#if defined (_CS_PATH) && defined (HAVE_CONFSTR) && !HAVE_DECL_CONFSTR
extern size_t confstr __P((int, char *, size_t));
#endif

extern int subshell_environment;

static void restore_path __P((char *));
static char *get_standard_path __P((void));

/* Run the commands mentioned in LIST without paying attention to shell
   functions. */
int
command_builtin (list)
     WORD_LIST *list;
{
  int result, verbose, use_standard_path, opt;
  char *old_path, *standard_path;
  COMMAND *command;

  verbose = use_standard_path = 0;
  reset_internal_getopt ();
  while ((opt = internal_getopt (list, "pvV")) != -1)
    {
      switch (opt)
	{
	case 'p':
	  use_standard_path = 1;
	  break;
	case 'V':
	  verbose = CDESC_SHORTDESC|CDESC_ABSPATH;	/* look in common.h for constants */
	  break;
	case 'v':
	  verbose = CDESC_REUSABLE;	/* ditto */
	  break;
	default:
	  builtin_usage ();
	  return (EX_USAGE);
	}
    }
  list = loptend;

  if (list == 0)
    return (EXECUTION_SUCCESS);

#if defined (RESTRICTED_SHELL)
  if (use_standard_path && restricted)
    {
      sh_restricted ("-p");
      return (EXECUTION_FAILURE);
    }
#endif

  begin_unwind_frame ("command_builtin");

  if (use_standard_path)
    {      
      old_path = get_string_value ("PATH");
      /* If old_path is NULL, $PATH is unset.  If so, we want to make sure
	 it's unset after this command completes. */
      if (old_path)
	old_path = savestring (old_path);
      add_unwind_protect ((Function *)restore_path, old_path);

      standard_path = get_standard_path ();
      bind_variable ("PATH", standard_path ? standard_path : "", 0);
      stupidly_hack_special_variables ("PATH");
      FREE (standard_path);
    }

  if (verbose)
    {
      int found, any_found;

      for (any_found = 0; list; list = list->next)
	{
	  found = describe_command (list->word->word, verbose);

	  if (found == 0 && verbose != CDESC_REUSABLE)
	    sh_notfound (list->word->word);

	  any_found += found;
	}

      run_unwind_frame ("command_builtin");
      return (any_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
    }

#define COMMAND_BUILTIN_FLAGS (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION | CMD_COMMAND_BUILTIN)

  /* We don't want this to be reparsed (consider command echo 'foo &'), so
     just make a simple_command structure and call execute_command with it. */
  command = make_bare_simple_command ();
  command->value.Simple->words = (WORD_LIST *)copy_word_list (list);
  command->value.Simple->redirects = (REDIRECT *)NULL;
  command->flags |= COMMAND_BUILTIN_FLAGS;
  command->value.Simple->flags |= COMMAND_BUILTIN_FLAGS;
#if 0
  /* This breaks for things like ( cd /tmp ; command z ababa ; echo next )
     or $(command echo a ; command echo b;) or even
     { command echo a; command echo b; } & */
  /* If we're in a subshell, see if we can get away without forking
     again, since we've already forked to run this builtin. */
  if (subshell_environment)
    {
      command->flags |= CMD_NO_FORK;
      command->value.Simple->flags |= CMD_NO_FORK;
    }
#endif
  add_unwind_protect ((char *)dispose_command, command);
  result = execute_command (command);

  run_unwind_frame ("command_builtin");

  return (result);
}

/* Restore the value of the $PATH variable after replacing it when
   executing `command -p'. */
static void
restore_path (var)
     char *var;
{
  if (var)
    {
      bind_variable ("PATH", var, 0);
      free (var);
    }
  else
    unbind_variable ("PATH");

  stupidly_hack_special_variables ("PATH");
}

/* Return a value for PATH that is guaranteed to find all of the standard
   utilities.  This uses Posix.2 configuration variables, if present.  It
   uses a value defined in config.h as a last resort. */
static char *
get_standard_path ()
{
#if defined (_CS_PATH) && defined (HAVE_CONFSTR)
  char *p;
  size_t len;

  len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0);
  if (len > 0)
    {
      p = (char *)xmalloc (len + 2);
      *p = '\0';
      confstr (_CS_PATH, p, len);
      return (p);
    }
  else
    return (savestring (STANDARD_UTILS_PATH));
#else /* !_CS_PATH || !HAVE_CONFSTR  */
#  if defined (CS_PATH)
  return (savestring (CS_PATH));
#  else
  return (savestring (STANDARD_UTILS_PATH));
#  endif /* !CS_PATH */
#endif /* !_CS_PATH || !HAVE_CONFSTR */
}
